var logger = require("../utils/log");

var socketMgr = require("./socket_service");
var roomMgr = require("./roommgr");
var mjUtils = require("./bbmjUtils");
var redis = require("../utils/redis");

var games = {};
var gamesSeats = {};

// const PERIOD_READY_0 = 0; //准备
// const PERIOD_HOLD_1 = 1; //发牌
// const PERIOD_GAME_2 = 2; //游戏阶段
// const PERIOD_SCORE_3 = 3; //计分阶段
// const PERIOD_IDLE_4 = 4; //空闲阶段

const PERIOD_READY = 0; //准备
const PERIOD_GAMING = 1; //游戏中
const PERIOD_END = 2; //游戏结束
// const PERIOD_DISSOLVING = 999; //正在请求解散

const MJ_GUO_ACTION = 0; //过动作
const MJ_PNEG_ACTION = 1; //碰动作
const MJ_GANG_DIAN_ACTION = 2; //点杠动作
const MJ_GANG_BU_ACTION = 3; //补杠动作
const MJ_GANG_AN_ACTION = 4; //暗杠动作
const MJ_CHI_ACTION = 5; //吃牌动作
const MJ_HU_ACTION = 6; //胡牌动作

var times = {};

//初始化数据
function setupGame(room) {
    //牌局共享的数据 包括状态 顺序 出牌
    var game = {
        room:room,
        numOfGames:0,
        type:room.conf.type,
        roomNo:room.roomNo,
    };
    game.plays = Object.keys(room.seats).length;//玩家数量 默认是4 也可以是3
    game.gameSeats = new Array(game.plays);//座位信息

    for (var index in room.seats) {
        var userInfo = room.seats[index];
        var seat = game.gameSeats[index] = {};

        seat.game = game;
        seat.seatIndex = index;//0 1 2 3
        seat.userId = userInfo.userId;

        gamesSeats[seat.userId] = seat;
    }

    games[room.roomNo] = game;
    refreshGame(game);

    return game;
};

function refreshGame(game) {
    game.memberOfReady = 0;//准备的人数
    game.memberOfAgree = 0;//同意的人数
    game.memberOfRefuse = 0;//拒绝的人数
    game.paiLength = 108;//牌的长度 蚌埠麻将144张字 108 + 28 + 8
    game.majongs = null;//麻将牌
    game.state = PERIOD_READY;//0等待游戏开始 1游戏进行中  999正在请求解散
    game.turn = 0;//当前轮到谁
    game.lastTurn = 0; //上次出牌的玩家 用于判定杠上开花
    game.lastGangPai = 0; //上次做出的动作 用于判定抢杠胡
    game.moPai = -1;//摸的牌
    game.chuPai = -1;//出的牌
    game.index = 0;//牌的下标

    game.mayPeng = null;//可以进行碰杠的用户
    game.mayHuArr = null;//可能的动作 2个胡牌 或者 3个胡牌
    game.mayActionLength = 0;
    game.didActionArr = null;//用户做出的动作 1个碰 2个胡牌 或者 3个胡牌 (最多只有一个碰)

    for (var i = 0; i < game.plays; i++) {
        var seat = game.gameSeats[i];

        seat.ready = false;
        //持有的牌
        seat.holds = [];
        //打出的牌
        seat.folds = [];
        //暗杠的牌
        seat.angangs = [];
        //点杠的牌(别人打直接杠)
        seat.diangangs = [];
        //补杠的牌(碰了之后再摸到牌杠)
        seat.bugangs = [];
        //碰了的牌
        seat.pengs = [];
        //摸到的花 摸到立即打出去
        seat.huas = [];

        //玩家手上的牌的数目，用于快速判定碰杠
        seat.countMap = {};
        //玩家听牌，用于快速判定胡了的番数 每次算牌都会新建{}
        seat.tingMap = null;

        //是否可以杠
        seat.canGang = false;
        //暗杠 补杠可能有多张 每次杠牌都会新建[] 专门用来表示 补杠和暗杠的合集
        seat.gangPais = null;
        //是否可以碰
        seat.canPeng = false;
        //是否可以胡
        seat.canHu = false;
        //是否可以出牌
        seat.canChuPai = false;
        //是否过牌
        seat.didAction = -1;

        seat.score = 0;

        //上次过胡 需要过一轮才能输
        seat.lastGuoHu = -1;
    }

    game.numOfGames++;
};

function xiPai(game) {
    var pkPais = new Array(game.paiLength); //蚌埠麻将带花 200张

    var index = 0;

    //万 1 ~ 9表示万
    for(var i = 1; i < 10; ++i){
        for(var j = 0; j < 4; ++j){
            pkPais[index] = i;
            index++;
        }
    }

    //条 11 ~ 19 表示条子
    for(var i = 11; i < 20; ++i){
        for(var j = 0; j < 4; ++j){
            pkPais[index] = i;
            index++;
        }
    }

    //筒 21 ~ 29 表示筒子
    for(var i = 21; i < 30; ++i){
        for(var c = 0; c < 4; ++c){
            pkPais[index] = i;
            index++;
        }
    }

    //东南西北中发白 31 ~ 37
    // for(var i = 31; i < 38; ++i){
    //     for(var c = 0; c < 4; ++c){
    //         pkPais[index] = i;
    //         index++;
    //     }
    // }

    //梅兰竹菊春夏秋冬 41 ~ 48
    // for(var i = 41; i < 49; ++i){
    //     pkPais[index] = i;
    //     index++;
    // }

    //乱序
    var length = game.paiLength - 1;
    for (var i = 0; i < length; i++) {
        var lastIndex = length-i;
        var temp = Math.floor(Math.random() * lastIndex);
        var t = pkPais[temp];
        pkPais[temp] = pkPais[lastIndex];
        pkPais[lastIndex] = t;
    }

    game.majongs = pkPais;
};

function faPai(game) {
    game.index = 0;

    //每人13张 一共 13*4 ＝ 52张 庄家多一张 53张
    var length = game.plays*13
    for (var i = 0; i < length; ++i){ //2 3 0 1
        moPai(game);
        moveToNextUser(game);
    }

    for (var i = 0; i < game.plays; i++) {
        var seat = game.gameSeats[i];
        seat.holds.sort(function (a, b) {
            return a - b;
        });
        // logger.debug("sorted holds", seat.holds);
    }
    socketMgr.notify_user_majongs(game);

    for (var i = 0; i < game.plays; ++i) {
        var seat = game.gameSeats[i];
        //自己只能自摸 或者 暗杠
        //别人只能碰 杠 胡
        checkCanTingPai(seat);
    }
    //庄家摸一张
    toMoPai(game);
    game.state = PERIOD_GAMING;
};

function moPai(game) {
    if (game.index == game.paiLength) return -1;

    var seat = game.gameSeats[game.turn];
    var pai = game.majongs[game.index];
    seat.holds.push(pai);

    //统计牌的数目 ，用于快速判定（空间换时间）
    var c = seat.countMap[pai];
    if (c == null) {
        c = 1;
    } else {
        c++;
    }
    seat.countMap[pai] = c;
    game.index++;

    return pai;
};

function chuPai(userId, pai){
    var seat = gamesSeats[userId];
    if (seat == null) return;

    var game = seat.game;
    //1，如果不该他出 则忽略  2，如果还有动作执行 则忽略
    if (game.turn != seat.seatIndex || hasOperations(seat)) return;

    pai = parseInt(pai);
    //从此人牌中扣除
    var index = seat.holds.indexOf(pai);
    if (index == -1) return;

    seat.holds.splice(index,1);
    game.chuPai = pai;
    game.moPai = -1;
    if (seat.countMap[pai] == 1) {
        delete seat.countMap[pai];
    } else {
        seat.countMap[pai]--;
    }

    socketMgr.notify_all_chupai(game);
    checkCanTingPai(seat);

    var mayPeng = null;
    var mayHuArr = [];
    var length = 0;
    for (var i = 0; i < game.plays; ++i){
        //玩家自己不检查
        logger.info('--------game.turn', game.turn);
        if (game.turn == i) continue;

        var tempSeat = game.gameSeats[i];
        checkUserOperation(tempSeat);
        var canPeng = tempSeat.canPeng || tempSeat.canGang;
        if (canPeng) mayPeng = tempSeat.userId;
        var canHu = tempSeat.canHu;
        if (canHu) mayHuArr.push(tempSeat.userId);
        if (canPeng || canHu) length++;
    }
    game.mayPeng = mayPeng;
    game.mayHuArr = mayHuArr;
    game.mayActionLength = length;
    logger.debug('length', length);

    //如果没有人有操作，则向下一家发牌，并通知他出牌
    if(length < 1){
        seat.folds.push(game.chuPai);
        setTimeout(function(){
            moveToNextUser(game);
            toMoPai(game);
        }, 1000);
    }
};

function moveToNextUser(game){
    game.lastTurn = game.turn;
    game.turn++;
    game.turn %= game.plays;
    logger.debug('moveToNextUser game turn', game.turn);
    return game.gameSeats[game.turn];
};

function moveToUser(game, index){
    game.lastTurn = game.turn;
    game.turn = index;
    game.turn %= game.plays;
    logger.debug('moveToUser game turn', game.turn);
    return game.gameSeats[game.turn];
};

function toMoPai(game){
    var seat = game.gameSeats[game.turn];
    var pai = moPai(game, game.turn);
    //牌摸完了，结束
    if(pai == -1){
        calcScore(game);
        return -1;
    }
    seat.holds.sort(function (a, b) {
        return a - b;
    });
    game.moPai = pai;
    game.chuPai = -1;
    socketMgr.notify_user_mopai(seat, pai);

    checkUserOperation(seat);
};

//检查听牌
function checkCanTingPai(seat){
    //每次检查听牌的就把之前的听牌清空
    seat.tingMap = {};

    //检查清一色
    var qingyise = isQingYiSe(seat);
    var fanshu = 1;
    if (qingyise) { //多5番
        fanshu += 5;
    }
    //门前清
    if (isMenQing(seat)) {
        fanshu += 1;
    }
    //杠
    fanshu += (seat.angangs.length*2);
    fanshu += seat.diangangs.length;
    fanshu += seat.bugangs.length;

    //检查对对胡
    var duiduiHu = checkDuiduiHu(seat);
    var length = duiduiHu.length;
    if (length > 0) {//是对对胡 是否判定7对
        for (var i = 0; i < length; i++) {
            var pai = duiduiHu[0];
            fanshu += 3;
            seat.tingMap[pai] = fanshu;
        }
    } else {//不是对对胡 是平胡或者清一色
        if (qingyise) {
            var type = getMJType(seat.holds[0])
            if (type == 0) {
                mjUtils.checkPingHu(seat, 1, 9);
            } else if (type == 1) {
                mjUtils.checkPingHu(seat, 11, 19);
            } else if (type == 2) {
                mjUtils.checkPingHu(seat, 21, 29);
            }
        } else {
            logger.debug('checkPingHu begin', Date.now());
            mjUtils.checkPingHu(seat, 1, 9);
            mjUtils.checkPingHu(seat, 11, 19);
            mjUtils.checkPingHu(seat, 21, 29);
            logger.debug('checkPingHu end', Date.now());
        }
        for (var pai in seat.tingMap) {
            seat.tingMap[pai] = fanshu;
        }
    }

    //如果听牌 则有seat.tingMap有值
    socketMgr.notify_user_tingpais(seat);
};

function isQingYiSe(seat){
    var type = getMJType(seat.holds[0]);

    if(!isSameType(type, seat.pengs)){
        return false;
    }
    if(!isSameType(type, seat.angangs)){
        return false;
    }
    if(!isSameType(type, seat.bugangs)){
        return false;
    }
    if(!isSameType(type, seat.diangangs)){
        return false;
    }
    //检查手上的牌
    if(!isSameType(type, seat.holds)){
        return false;
    }
    return true;
};

function isSameType(type, arr){
    var length = arr.length;
    for(var i = 0; i < length; ++i){
        var temp = getMJType(arr[i]);
        if(temp != type){
            return false;
        }
    }
    return true;
};

function isMenQing(seat){
    return (seat.pengs.length + seat.bugangs.length + seat.diangangs.length) == 0;
};

function checkDuiduiHu(seat) {
    //检查是否是对对胡  只需要检查手上的牌
    //对对胡叫牌有两种情况
    //1、N坎 + 1张单牌
    //2、N-1坎 + 两对牌
    var singleCount = 0;
    var pairCount = 0;
    var colCount = 0;

    //可以放听牌的字段
    var arr = [];
    for (var i in seat.countMap) {
        var c = seat.countMap[i];
        if (c == 1){
            singleCount++;
            arr.push(i);
        } else if(c == 2){
            pairCount++;
            arr.push(i);
        } else if(c == 3) {
            colCount++;
        } else if(c == 4) {//手上有4个一样的牌，当成两对
            pairCount +=2;
        }
    }
    //区分对对胡 和 单吊
    if ((pairCount == 2 && singleCount == 0) || (pairCount == 0 && singleCount == 1)) {
        return arr;
    }
    return new Array(0);
};

//检查用户可能的操作
function checkUserOperation(seat) {
    var game = seat.game;

    logger.debug("--------checkUserOperation", seat.seatIndex);
    seat.gangPais = [];
    if (seat.seatIndex == game.turn) { //是自己的顺序 判断暗杠 自摸
        logger.debug("--------checkMyOperation");
        checkCanBuGang(seat);
        checkCanAnGang(seat);
        seat.canGang = seat.gangPais.length > 0;

        //检查胡
        checkCanHu(seat);
    } else { //判断碰杠胡
        logger.debug("--------checkOtherOperation");
        var can = checkCanDianGang(seat);
        if (can) {
            seat.canPeng = true;
        } else {
            checkCanPeng(seat);
        }
        //检查胡
        checkCanHu(seat);
    }
    if(hasOperations(seat)){
        seat.didAction = -1;
        sendOperations(seat);
    }
};

//检查是否可以暗杠
function checkCanAnGang(seat){
    // seat.canGang = false;

    var game = seat.game;
    //如果没有牌了，则不能再杠
    if(game.index == game.paiLength) return false;

    for(var key in seat.countMap){
        var c = seat.countMap[key];
        if(c == 4){
            // seat.canGang = true;
            seat.gangPais.push(key);
        }
    }
    // return seat.canGang;
};

//检查是否可以补杠(碰了之后再摸到牌杠)
function checkCanBuGang(seat){
    // seat.canGang = false;
    var game = seat.game;
    //如果没有牌了，则不能再杠
    if(game.index == game.paiLength)return false;

    //从碰过的牌中选
    var length = seat.pengs.length;
    for(var i = 0; i < length; ++i){
        var pai = seat.pengs[i];//碰过
        if(seat.countMap[pai] == 1){ //手牌还有一张
            // seat.canGang = true;
            seat.gangPais.push(pai);
        }
    }
    // return seat.canGang;
};

//检查是否可以点杠(别人打直接杠)
function checkCanDianGang(seat){
    seat.canGang = false;
    var game = seat.game;
    //如果没有牌了，则不能再杠
    if(game.index == game.paiLength) return false;

    var count = seat.countMap[game.chuPai];
    if(count == 3){
        seat.canGang = true;
    }
    return seat.canGang;
};

//检查是否可以碰
function checkCanPeng(seat) {
    var game = seat.game;
    seat.canPeng = false;
    var count = seat.countMap[game.chuPai];
    if(count == 2){
        seat.canPeng = true;
    }
    return seat.canPeng;
};

//检查是否可以胡
function checkCanHu(seat) {
    var game = seat.game;
    seat.canHu = false;
    if (seat.seatIndex == game.turn) { //是自己的顺序 自摸
        if (seat.tingMap[game.moPai]) {
            seat.canHu = true;
        }
    } else {
        if (seat.tingMap[game.chuPai]) {
            seat.canHu = true;
        }
    }
    return seat.canHu;
};

function hasOperations(seat) {
    if(seat.canGang || seat.canPeng || seat.canHu) return true;
    return false;
};

function sendOperations(seat) {
    var data = {
        hu:seat.canHu,
        peng:seat.canPeng,
        gang:seat.canGang,
        chi:false,
        gangPais:seat.gangPais,
    };
    socketMgr.notify_user_operate_available(seat, data);
};

function peng(userId) {
    var seat = gamesSeats[userId];
    if(seat == null || !seat.canPeng) return;

    var game = seat.game;
    //不能胡 只能碰杠
    if (game.mayActionLength == 1) {
        doPeng(seat);
        return;
    }
    //能碰 且所有人都做了动作
    if (game.didActionArr.length == game.mayActionLength) {
        doAction(game);
        return;
    }
    if (game.didActionArr == null) game.didActionArr = [];
    game.didActionArr.push(seat.userId);
    seat.didAction = MJ_PNEG_ACTION;
};

function doPeng(seat) {
    var game = seat.game;
    clearAllOptions(game);

    var pai = game.chuPai;
    var c = seat.countMap[pai];
    if(c < 2) return;

    for(var i = 0; i < 2; ++i){
        spliceHolds(seat, pai);
    }

    seat.pengs.push(pai);
    socketMgr.notify_all_user_operate(seat, MJ_PNEG_ACTION, pai);

    moveToUser(game, seat.seatIndex);
    //碰了之后 只能出牌或者暗杠,补杠 出牌时会做听牌检查
    checkUserOperation(seat);
};

function gang(userId, pai) {
    var seat = gamesSeats[userId];
    if(seat == null || !seat.canGang) return;

    var game = seat.game;
    //是自己摸牌 那就是补杠 或者 暗杠
    if (game.turn == seat.seatIndex) {
        doGang(seat, pai);
        return;
    }
    //不能胡 只能碰杠
    if (game.mayActionLength == 1) {
        doGang(seat);
        return;
    }
    //能胡 且所有人都做了动作
    if (game.didActionArr.length == game.mayActionLength) {
        doAction(game);
        return;
    }
    if (game.didActionArr == null) game.didActionArr = [];
    game.didActionArr.push(seat.userId);
    seat.didAction = MJ_GANG_DIAN_ACTION;
};

function doGang(seat, pai) {
    var game = seat.game;
    clearAllOptions(game);

    if (pai == null) pai = game.chuPai;

    game.lastGangPai = 0;
    var type = -1;
    //只能有一个人碰杠
    if (game.turn == seat.seatIndex) { //是自己的轮 那就是补杠 或者 暗杠
        if (seat.countMap[pai] == 4) { //暗杠
            for(var i = 0; i < 4; ++i){
                spliceHolds(seat, pai);
            }
            seat.angangs.push(pai);
            type = MJ_GANG_AN_ACTION;
        } else if (seat.countMap[pai] == 1) { //补杠
            spliceHolds(seat, pai);

            seat.bugangs.push(pai);
            type = MJ_GANG_BU_ACTION;

            game.lastGangPai = pai;
        }
    } else { //是点杠
        for(var i = 0; i < 3; ++i){
            spliceHolds(seat, pai);
        }
        seat.diangangs.push(pai);
        type = MJ_GANG_DIAN_ACTION;

        game.lastGangPai = pai;
    }
    socketMgr.notify_all_user_operate(seat, type, pai);

    if (game.lastGangPai) { //todo 检查抢杠胡

    }

    //去做听牌检查
    checkCanTingPai(seat);

    //杠了之后 只能去摸牌
    moveToUser(game, seat.seatIndex);
    toMoPai(game);
};

function hu(userId, pai) {
    var seat = gamesSeats[userId];
    if(seat == null || !seat.canHu) return;

    var game = seat.game;
    //是自己摸牌 且能胡 那就是自摸
    if (game.turn == seat.seatIndex) {
        doHu(seat, pai);
        return;
    }
    //只有一家能胡
    if (game.mayActionLength == 1 || game.mayHuArr.length == 1) {
        doHu(seat);
        return;
    }
    //多家胡 且所有人都做了动作
    if (game.didActionArr.length == game.mayActionLength) {
        doAction(game);
        return;
    }
    if (game.didActionArr == null) game.didActionArr = [];
    game.didActionArr.push(seat.userId);
    seat.didAction = MJ_HU_ACTION;
};

function doHu(seat, pai) {
    logger.debug('dohu', seat.seatIndex);
    if (seat == null) return;

    var game = seat.game;
    if (pai == null) pai = game.chuPai;
    logger.debug('dohu', pai);

    var huData = {
        userId:seat.userId,
        pai:pai,
        fan:seat.tingMap[pai],
    };
    var isZimo = game.turn == seat.seatIndex;
    huData.isZimo = isZimo;

    if (isZimo) {
        huData.isGangHu = game.lastTurn == seat.seatIndex;
    } else {
        huData.target = game.gameSeats[game.turn].userId;
        huData.isQiangGangHu = game.lastGangPai == pai;
    }
    huData.isQingyise = isQingYiSe(seat);
    huData.isDuiduiHu = checkDuiduiHu(seat);

    socketMgr.notify_all_user_operate(seat, MJ_HU_ACTION, pai);

    moveToUser(game, seat.seatIndex);
    calcScore(game, huData);

    logger.debug('numOfGames', game.numOfGames);
    if (game.numOfGames == game.room.conf.jushu) {
        endGame(game);
    } else {
        var resultInfo = sortResult(game);
        socketMgr.notify_game_result(game, resultInfo);
    }
};

function guo(userId) {
    var seat = gamesSeats[userId];
    if (seat == null || !hasOperations(seat)) return -1;

    //这里还要处理过胡的情况
    var game = seat.game;
    //是自己摸牌 且能胡 那就是自摸
    if (game.turn == seat.seatIndex) {
        doGuo(seat);
        return;
    }
    //不是自己出牌 且能胡 算过胡
    if (seat.seatIndex != game.turn && seat.canHu) {
        seat.lastGuoHu = game.chuPai;
    }
    //只有一家能胡
    if (game.mayActionLength == 1) {
        doGuo(seat);
        return;
    }
    //多家胡 且所有人都做了动作
    if (game.didActionArr.length == game.mayActionLength) {
        doAction(game);
        return;
    }
    if (game.didActionArr == null) game.didActionArr = [];
    game.didActionArr.push(seat.userId);
    seat.didAction = MJ_GUO_ACTION;
};

function doGuo(seat) {
    var game = seat.game;
    clearAllOptions(game);

    var lastSeat = game.gameSeats[game.turn];
    lastSeat.folds.push(game.chuPai);
};

function doAction(game) {
    //必定是能进行多个动作 才到这一步
    var seat = null;
    var turn = game.turn;
    logger.debug('doAction game turn', game.turn);
    var length = game.mayHuArr.length;
    //0    1 2 3    4    1 2 3
    //2    3 0 1    2    3 4 1
    //3    0 1 2    3    4 1 2
    for (var i = 0; i < length; i++) {
        turn ++;
        turn %=4;
        var uid = game.mayHuArr[i];
        var tempSeat = gamesSeats[uid];
        if (turn == tempSeat.seatIndex && seat.didAction == MJ_HU_ACTION) {
            seat = tempSeat;
            break;
        }
    }
    if (seat == null) {
        seat = gamesSeats[game.mayPeng];
        if (seat.didAction == MJ_PNEG_ACTION) {
            doPeng(seat);
        } else if (seat.didAction == MJ_GANG_DIAN_ACTION){
            doGang(seat);
        }
        for (var i = 0; i < game.mayActionLength; i++) {
            var uid = game.didActionArr[i];
            var tempSeat = gamesSeats[uid];
            doGuo(tempSeat);
        }
    } else {
        doHu(seat);
    }
};

function spliceHolds(seat, pai) {
    var index = seat.holds.indexOf(pai);
    seat.holds.splice(index,1);
    seat.countMap[pai] --;
    if (seat.countMap[pai] == 0) {
        delete seat.countMap[pai];
    }
};

function clearAllOptions(game){
    for (var i = 0; i < game.plays; i++) {
        var seat = game.gameSeats[i];
        seat.canPeng = false;
        seat.canGang = false;
        seat.canHu = false;
        seat.didAction = -1;
    }
};

//开始游戏
function beginGame(userId, roomNo) {
    if (!roomMgr.isCreator(roomNo, userId)) return;
    var room = roomMgr.getRoomByRoomNo(roomNo);
    if(room == null) {
        logger.error("begin error", roomNo);
        return;
    }
    var game = setupGame(room);
    xiPai(game);
    faPai(game);
};

//准备
function ready(userId) {
    var seat = gamesSeats[userId];
    var game = seat.game;
    if (!seat.ready) {
        game.memberOfReady++;
        seat.ready = true;
    }
    //如果所有人都准备完成 更改游戏计数器
    if (game.memberOfReady == game.plays) {
        refreshGame(game);
        xiPai(game);
        faPai(game);
    }
};

//统计当局结果信息
function sortResult(game) {
    var resultInfo = {};
    for (var i = 0; i < game.plays; i++) {
        var seat = game.gameSeats[i];
        var info = {
            score: seat.score,
            holds: seat.holds,
        };
        resultInfo[seat.userId] = info;
    }
    return resultInfo;
}

//算积分
function calcScore(game, huData) {
    game.state = PERIOD_END;

    setupGameStatistics(game);
    var statistics = game.room.statistics;

    var score = huData.fan;
    var winUserId = huData.userId;
    var shuUserId = huData.isZimo ? null : huData.target;
    for (var i = 0; i < game.plays; i++) {
        var seat = game.gameSeats[i];
        var info = statistics[seat.userId];

        info.dianGang += seat.diangangs.length;
        info.anGang += seat.angangs.length;
        if (huData.isZimo) {
            if (seat.userId == winUserId) {
                info.ziMo += 1;
                seat.score = score*game.plays;
                info.score += seat.score;
            } else {
                info.dianPao += 1;
                seat.score = -score;
                info.score += seat.score;
            }
        } else {
            if (seat.userId == winUserId) {
                info.jiePao += 1;
                seat.score = score;
                info.score += seat.score;
            } else if (seat.userId == shuUserId){
                info.dianPao += 1;
                seat.score = -score;
                info.score += seat.score;
            }
        }
    }
    redis.cacheRoomGameResult(game.roomNo, JSON.stringify(game.room.statistics))
};

function setupGameStatistics(game) {
    var statistics = game.room.statistics;
    if (statistics != null && Object.keys(statistics).length < 1) {
        for (var i = 0; i < game.plays; i++) {
            var seat = game.gameSeats[i];
            var info = statistics[seat.userId];
            if (info == null) {
                info = {
                    dianGang: 0,
                    anGang: 0,
                    ziMo: 0,
                    dianPao: 0,
                    jiePao: 0,
                    score: 0,
                };
                statistics[seat.userId] = info;
            }
        }
    }
};

//结束游戏
function endGame(game, force){
    setupGameStatistics(game);
    socketMgr.notify_game_end_statistics(game);
    //延迟2S 做断开socket 清理room操作
    setTimeout(function () {
        //关闭房间
        roomMgr.closeRoom(game.room.creator, game.room.roomNo);
        //踢出所有房间socket
        socketMgr.knockout_all(game);
        //清楚房间信息
        delGameInfo(game);
    }, 2000);
};

//清除游戏信息
function delGameInfo(game) {
    for (var i = 0; i < game.plays; i++) {
        var seat = game.gameSeats[i];
        delete gamesSeats[seat.userId];
    }
    delete games[game.roomNo];
    delete times[game.roomNo];
};

//解散请求处理
function dissolveRequest(userId, operate) {
    var seat = gamesSeats[userId];
    var game = seat.game;
    if (operate == 1) { //同意
        game.memberOfAgree++;
    } else {
        game.memberOfRefuse++;
    }
    if (game.memberOfRefuse > 0 || game.memberOfAgree == game.plays) { //超过1人拒绝 或者 所有人都同意
        var timeout = times[game.roomNo];
        if (timeout) {
            clearTimeout(timeout);
            delete times[game.roomNo];
        }
        if (game.memberOfRefuse > 0) {
            socketMgr.notify_dissolve_result(game, 0);
        } else {
            socketMgr.notify_dissolve_result(game, 1);

            //强制结束游戏
            endGame(game, true);
        }
        game.memberOfRefuse = 0;
        game.memberOfAgree = 0;
        return;
    }
    if (times[game.roomNo] == null) {
        var timeout = setTimeout(function () {
            socketMgr.notify_dissolve_result(game, 0);
            delete times[game.roomNo];
        }, 60000);//60s后
        times[game.roomNo] = timeout;
    }
};

//游戏类型
function gameState(roomNo) {
    var game = games[roomNo];
    if (game == null) return -1;
    return game.state;
};

//获取game对象
function getGameByRoomNo(roomNo) {
    return games[roomNo];
}
//MJ牌类型
function getMJType(pai){
    //9*4*3=108张 东南西北中发白7*4*3=84张 梅兰竹菊春夏秋冬8*1
    if(pai > 0 && pai < 10){//万 1 2 3 4 5 6 7 8 9
        return 0;
    } else if(pai > 10 && pai < 20){//条 11 12 13 14 15 16 17 18 19
        return 1;
    } else if(pai > 20 && pai < 30){//筒 21 22 23 24 25 26 27 28 29
        return 2;
    } else if(pai > 30 && pai < 40) {//东南西北中发白
        return 3;
    } else if(pai > 40 && pai < 50) {//梅兰竹菊春夏秋冬
        return 4;
    }
};

exports.getGameByRoomNo = getGameByRoomNo;

// exports.setupGame = setupGame;
exports.ready = ready;
exports.beginGame = beginGame;
// exports.calcScore = calcScore;
// exports.readyNextGame = readyNextGame;
exports.endGame = endGame;
exports.dissolveRequest = dissolveRequest;
exports.gameState = gameState;

exports.chuPai = chuPai;
exports.peng = peng;
exports.gang = gang;
exports.hu = hu;
exports.guo = guo;




















